functions with variable arguments

Hello,

Is there a way to declare a function with a variable number of arguments like this
 

void someFunction(int a,real b,Array varargin){ // varargin would be a keyword like in Scilab
   ...
}

 


Then someFunction can be called with 2 or more arguments, and arguments following the second one can be of any type --- it is up to someFunction to detect any semantic error. It would be up to someFunction to delete varargin.

I raise the question because I developed some sprintf function, and I need to make those few overloads:

 

 

 

string sprintfEngine_(string fmt, Array args){
    Buffer oBuffRet = create
 
 
        delete args
        return stringOf oBuffRet
}
 
 
string sprintf(string fmt,real a0){
        Array args = create(1,1)
        put(args,a0,0,0)
        return sprintfEngine_(fmt,args)
}
string sprintf(string fmt,real a0,a1){
        Array args = create(2,1)
        put(args,a0,0,0)
        put(args,a1,1,0)
        return sprintfEngine_(fmt,args)
}
 
string sprintf(string fmt,string a0, real a1){
        Array args = create(2,1)
        put(args,a0,0,0)
        put(args,a1,1,0)
        return sprintfEngine_(fmt,args)
}
 
string sprintf(string fmt,real a0, string a1){
        Array args = create(2,1)
        put(args,a0,0,0)
        put(args,a1,1,0)
        return sprintfEngine_(fmt,args)
}
 
string sprintf(string fmt,real a0,a1,a2){
        Array args = create(3,1)
        put(args,a0,0,0)
        put(args,a1,1,0)
        put(args,a2,2,0)
        return sprintfEngine_(fmt,args)
}
 
string sprintf(string fmt,real a0,string a1,real a2){
        Array args = create(3,1)
        put(args,a0,0,0)
        put(args,a1,1,0)
        put(args,a2,2,0)
        return sprintfEngine_(fmt,args)
}

 

 


SystemAdmin - Wed Feb 16 04:28:39 EST 2011

Re: functions with variable arguments
llandale - Wed Feb 16 13:32:39 EST 2011

Don't understand the question. But it appears you understand how to do it, yes you write several functions all with the same output parameter and all with the same name, but with different number and types of parameters. Typically the "first" one has the most paramters, and the additional ones default them to various values.

string Find(string In_String, bool MatchCase)
{...
}
string Find(string In_String)
{  return(Find(In_String, true))
}  // end overloaded Find(yes MatchCase)


So your "Help" may make it look like there's a single function with variable parameters

"string Find(string, bool MatchCase) Matchcase defaulted to true"

but there is still two functions.

There is some mechanism for defining "any type of variable" but gads, what's the point unless you just want to print the variable's address.

 

 

  • Louie


PS. Avoid creating the Buffer inside the function and failing to delete it. I'd move it out of the function to become a global variable, perhaps rename it to "oBuffRet_sprintf". If you do that, then you cannot return the "tempStringOf" unless you KNOW the output is going to be disposed of immediately and not reused, such as printing or assignment to some attr-value.

 

 

Re: functions with variable arguments
Mathias Mamsch - Wed Feb 16 14:21:47 EST 2011

You can indeed do this, but only for functions that take parameters of the same type:
 

int func (int ar[]) { return sizeof ar }
print func (3,4,5) 
print func (6,7,8,9,10)

 


A nice undocumented feature of DXL. However if you want to have different types you need to switch the normal calling syntax to binary operators, that take an underscore type as right hand argument:

 

 

 

string sprintf(string s, Skip x) {
    int parCount = 0; find (x, 0, parCount) 
        print "Formatting the string '" s "' with: " parCount " parameters\n"
 
        int i; for i in 1:parCount do {
                int val = 0;   // read the parameter as integer
                if (find(x, i, val)) {
                        if (i > 1) print ", "
                        print val ""
                }
        }
        delete sk 
        return ""
}
 
Skip with () {
        Skip result = create(); 
        put (result, 0,0) 
        return result
}
 
Skip ::<- (Skip x, _y val) {
        int count = 0; find (x, 0, count); 
        put (x, count+1, val) 
        put (x, 0, count+1, true)
        return x
}
 
string s = "My String" 
string newss = sprintf ("MyFormat String %d %s", with <- 10 <- s)



Other syntaxes might possible, e.g.



 

 

 

//  Use MyType ::<- (string, _y)  and MyType ::<- (MyType, _x) and sprintf (MyType) 
    string s = sprintf "FormatString" <- 10 <- s

 

 

 


Mathias Mamsch, IT-QBase GmbH, Consultant for Requirement Engineering and D00RS

 

 

Re: functions with variable arguments
SystemAdmin - Thu Feb 17 06:03:30 EST 2011

To Louie,

The reason for not wanting to use a number of function declaration is that the combinatory means lots of declarations. Assume that the types after string fmt in sprintf may be int, real or string. Then
for zero extra argument I need 1 declaration
for one extra arguments I need 3 declarations
for two extra arguments I need 3^2 declarations
for thee extra arguments I need 3^3 declarations

So in total (3^4-1)/(3-1) = 40 declarations.

After all I don't think that I would ever need more then 3 extra arguments --- any how one can concatenate outputs.

Re: functions with variable arguments
SystemAdmin - Thu Feb 17 08:11:37 EST 2011

Hello Mathias,

Just for my clarification are _x and _y reserved keywords? They do not seem to be documented ...

Is MyType just any type. It does not seems that you can define new types in DXL (like with typedef, class, union, enum or struct in C/C++).

Vincent.

Re: functions with variable arguments
Mathias Mamsch - Thu Feb 17 15:15:50 EST 2011

SystemAdmin - Thu Feb 17 08:11:37 EST 2011
Hello Mathias,

Just for my clarification are _x and _y reserved keywords? They do not seem to be documented ...

Is MyType just any type. It does not seems that you can define new types in DXL (like with typedef, class, union, enum or struct in C/C++).

Vincent.

Hi Vicent,

Types beginning with an underscrore are treated specially from DOORS. This is not a documented feature of DXL. You can pass any kind of parameter to them(string, real, Module, whatever). That is why a Skip list for example will take any key and value, without DXL defining a prototype function for each key/value type pair. Special care has to be taken when using underscore types in functions, they can very quickly make your code crash, if not handled correctly. You should take a look at the DOORS undocumented perms list, to see how array, Skip, etc. have their put() find() etc methods defined.

As for creating new types, this is indeed possible in DXL but also undocumented. See this post and others (search for struct). Usually for doing those syntax 'games' it is better to declare a custom type, so you will not litter your namespace. I say 'games', because this will only give you a nicer cleaner syntax, after all you can still just do
 

string sprintf (string sFmt, Array a) {... }
   
   Array ar = create(3,1); put (ar, var1, 1, 1); put (ar, var2, 2, 1); sprintf("%d %s", ar);

 


everytime you call sprintf. So using the syntax enhancement with operators, instead of this you can then write:

 

 

 

sprintf ("%d %s", var1 <- var2)



which is a little shorter, but still the same thing. Hope this helps, regards, Mathias



 

 

 

 


Mathias Mamsch, IT-QBase GmbH, Consultant for Requirement Engineering and D00RS

 

 

Re: functions with variable arguments
Mathias Mamsch - Thu Feb 17 15:32:23 EST 2011

SystemAdmin - Thu Feb 17 08:11:37 EST 2011
Hello Mathias,

Just for my clarification are _x and _y reserved keywords? They do not seem to be documented ...

Is MyType just any type. It does not seems that you can define new types in DXL (like with typedef, class, union, enum or struct in C/C++).

Vincent.

Here is the example with the modified syntax. I choose the -> operator because it has higher precedence and will let us do the call completly without braces.
 

struct SPrintfDummyType {}
 
SPrintfDummyType ::-> (string sfmt, _y val) {
    DxlObject x = new() 
        x->"fmt" = sfmt
        Skip sk = create() 
        put (sk, 0,1) 
        put (sk, 1, val) 
        x->"skip" = sk
        return (addr_ x) SPrintfDummyType 
}
 
SPrintfDummyType  ::-> (SPrintfDummyType var, _y val) {
        DxlObject dx = (addr_ var) DxlObject
      Skip sk = dx->"skip"
        int count = 0; find (sk , 0, count); 
        put (sk, count+1, val) 
        put (sk, 0, count+1, true)
      return var
}
 
string sprintf(SPrintfDummyType var) {
        DxlObject dx = (addr_ var) DxlObject
        Skip x = (dx->"skip") Skip
        string s = (dx->"fmt") string
 
        int parCount = 0; find (x, 0, parCount) 
        print "Formatting the string '" s "' with: " parCount " parameters\n"
 
        int i; for i in 1:parCount do {
                int val = 0;   // read the parameter as integer
                if (find(x, i, val)) {
                        if (i > 1) print ", "
                        print val ""
                }
        }
      delete x
      print "\n"
        return "insert formatted string here"
}
 
string s = "Hello"
real r = 0.1
Date d = today() 
// probably an even nicer syntax ...
string result = sprintf "MyFormat String %d %s %r %D" -> 10 -> s -> r -> d
print result "\n"

 


Regards, Mathias

 

 

 


Mathias Mamsch, IT-QBase GmbH, Consultant for Requirement Engineering and D00RS

 

 

Re: functions with variable arguments
SystemAdmin - Fri Feb 18 07:51:16 EST 2011

By the way,

thank you for all the code you have put on this forum. Here is the code of sprintf which I am using.
 

Regexp greSprintfFixedPointNumber_ = regexp2 "^([0-9]+)?(\\.([0-9]+))?$"
Regexp greSprintfAllZero_ = regexp2 "^0*$"
 
Regexp greSprintfFmtMark_ = regexp2 "%"
Regexp greSprintfFixedPoint_ = regexp2 "^\\.([0-9]+)f"
 
 
 
string stringOfReal_(real rInput, int iFractionSize, bool bTruncateZeros){
    real rPrecision = (exp ((realOf iFractionSize) * 2.302585092994046))
        real rToBeRounded = rInput * rPrecision
        if rToBeRounded < 2147483646.5 and rToBeRounded > -2147483647.5 then  
                rInput = (realOf (intOf rToBeRounded))/rPrecision
        string sInput = rInput ""
 
 
        if(greSprintfFixedPointNumber_ sInput){
                int iEndFactionalPart = start 2
                if(iEndFactionalPart >= 0){
                        iEndFactionalPart += iFractionSize+1
                        if((length sInput) > iEndFactionalPart){
                                if bTruncateZeros and (greSprintfAllZero_ sInput[iEndFactionalPart:]) then{
                                        int i = (length sInput) -1
                                        while (sInput[i : i] == "0") --i
                                        sInput = sInput[0 : i]
 
                                }
                                else
                                        sInput = sInput[0 : (iEndFactionalPart-1)]
                        }
                        else if(bTruncateZeros){
                                int i = (length sInput) -1
                                while (sInput[i : i] == "0") --i
                                sInput = sInput[0 : i]
                        }
                        else
                        {
                                int i = (length sInput) - iEndFactionalPart
                                if i >= 1 then{
                                        Buffer oBuff = create
                                        oBuff = sInput
                                        for i in i : 1 by -1 do oBuff += "0"
                                        sInput = stringOf oBuff
                                }
                        }
                }
                else if(bTruncateZeros){
                        int i = (length sInput) -1
                        while (sInput[i : i] == "0") --i
                        sInput = sInput[0 : i]
                }
                else
                {
                        Buffer oBuff = create
                        oBuff = sInput
                        oBuff += "."
                        int i
                        for i in iFractionSize : 1 by -1 do oBuff += "0"
                        sInput = stringOf oBuff
                }
                        
        }
 
        return sInput
                
}
 
 
string sprintf(string fmt, Array args){
        Buffer oBuffRet = create
        int iSearchStart = 0
        int iArrayEltIndex = 0
 
        while(greSprintfFmtMark_ fmt[iSearchStart :]){
                int iFoundStart = iSearchStart + (start 0)
                if iFoundStart > iSearchStart then
                        oBuffRet += fmt[iSearchStart : (iFoundStart-1)]
                iSearchStart = iFoundStart+1
                if(greSprintfFixedPoint_ fmt[iSearchStart : ]){
                        int iFractionSize = intOf (realOf (fmt[(iSearchStart +  start 1):(iSearchStart +  end 1)]))
                        real rVal = (real (get(args,iArrayEltIndex++,0)))
                        oBuffRet += stringOfReal_(rVal, iFractionSize, false)
                        iSearchStart += (end 0) + 1
                }
                else if(fmt[iSearchStart : iSearchStart] == "f"){
                        oBuffRet += (real (get(args,iArrayEltIndex++,0))) ""
                        iSearchStart += 1
                }
                else if(fmt[iSearchStart : iSearchStart] == "s"){
                        oBuffRet += (string (get(args,iArrayEltIndex++,0)))
                        iSearchStart += 1
                }
                else if(fmt[iSearchStart : iSearchStart] == "c"){
                        oBuffRet += charOf (int (get(args,iArrayEltIndex++,0)))
                        iSearchStart += 1
                }
                else if(fmt[iSearchStart : iSearchStart] == "d"){
                        oBuffRet += (int (get(args,iArrayEltIndex++,0))) ""
                        iSearchStart += 1
                }
                else if(fmt[iSearchStart : iSearchStart] == "%"){
                        oBuffRet += "%"
                        iSearchStart += 1
                }
                else
                        error ("Invalid formatter=\"%" fmt[iSearchStart :] "\".\n\tiSearchStart=" (iSearchStart ".\n"))
                
 
        }
        oBuffRet += fmt[iSearchStart :]
        return stringOf oBuffRet
}
 
string sprintfEngine_(string fmt, Array args){
        string ret = sprintf(fmt,args)
        delete args
    return ret
}
 
 
string sprintf(string fmt,real a0){
        Array args = create(1,1)
        put(args,a0,0,0)
        return sprintfEngine_(fmt,args)
}
string sprintf(string fmt,int a0){
        Array args = create(1,1)
        put(args,a0,0,0)
        return sprintfEngine_(fmt,args)
}
 
string sprintf(string fmt,real a0,a1){
        Array args = create(2,1)
        put(args,a0,0,0)
        put(args,a1,1,0)
        return sprintfEngine_(fmt,args)
}
 
string sprintf(string fmt,string a0, real a1){
        Array args = create(2,1)
        put(args,a0,0,0)
        put(args,a1,1,0)
        return sprintfEngine_(fmt,args)
}
 
string sprintf(string fmt,real a0, string a1){
        Array args = create(2,1)
        put(args,a0,0,0)
        put(args,a1,1,0)
        return sprintfEngine_(fmt,args)
}
 
string sprintf(string fmt,real a0,a1,a2){
        Array args = create(3,1)
        put(args,a0,0,0)
        put(args,a1,1,0)
        put(args,a2,2,0)
        return sprintfEngine_(fmt,args)
}
 
string sprintf(string fmt,real a0,string a1,real a2){
        Array args = create(3,1)
        put(args,a0,0,0)
        put(args,a1,1,0)
        put(args,a2,2,0)
        return sprintfEngine_(fmt,args)

 


For the time being I prefer to add the few prototypes which I need, rather than use skip lists and the <- operator which you recommend in the hope that one day DXL will support sprintf with a variable number of arguments.